/*************************************************************************
	> File Name: signal.c
	> Author: Thinking
	> Mail: program_code@sohu.com 
	> Created Time: Wed 16 Jun 2021 05:45:46 AM PDT
 ************************************************************************/

#include <linux/lsm_hooks.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kprobes.h>
#include <linux/kallsyms.h>
#include <linux/binfmts.h>

#define MAX_RO_PAGES 1024

struct security_hook_heads srt_dummy_hooks;

#define SRT_HOOK_INIT(HEAD, HOOK) \
	    { \
			.head = &srt_dummy_hooks.HEAD, .hook = {.HEAD = HOOK } \
		}

static inline void add_hook(struct security_hook_list *hook)
{
	list_add_tail_rcu(&hook->list, hook->head);
}

static void __init swap_hook(struct security_hook_list *hook,
					     union security_list_options *original)
{
	struct list_head *list = hook->head;
	if (list_empty(list)) {
		add_hook(hook);
	} else {
		struct security_hook_list *shp = list_last_entry(list, struct security_hook_list, list);
		*original = shp->hook;
		smp_wmb();
		shp->hook = hook->hook;
	}
}




static char * srt_get_dentry_path(struct dentry *dentry, char * const buffer, const int buflen)
{
	char *pos = ERR_PTR(-ENOMEM);
	if (buflen >= 256) {
		pos = dentry_path_raw(dentry, buffer, buflen - 1);
		printk("run dentry_path_mkdir:%s=>%s\n", pos, buffer);
		if (!IS_ERR(pos) && *pos == '/' && pos[1] && d_is_dir(dentry)) {
			buffer[buflen - 2] = '/';
			buffer[buflen - 1] = '\0';
		}
	}
	return pos;
}


#define CCS_GFP_FLAGS GFP_NOFS

#ifdef CONFIG_SECURITY_PATH
static int srt_path_mkdir(struct path *dir, struct dentry *dentry, umode_t mode)
{
	//printk("run linx_path_mkdir:%s\n", dentry->d_name.name);

	char *buf = NULL;

	unsigned int buf_len = 4096;

	buf = kmalloc(buf_len, CCS_GFP_FLAGS);

	buf[buf_len - 1] = '\0';

	srt_get_dentry_path(dentry, buf, buf_len - 1);

	printk("run linx_path_mkdir:%s=>%s\n", buf, dentry->d_name.name);

	if(buf)
		kfree(buf);

	return 0;
}
#else
static int srt_inode_mkdir(struct inode* dir, struct dentry* dentry, umode_t mode)
{
	printk("run linx_inode_mkdir:%s\n", dentry->d_name.name);
    return 0;
}
#endif

static int srt_bprm_set_creds(struct linux_binprm *bprm)
{
	printk("bprm_set %s\n", bprm->filename);
	return 0;
}

static struct security_hook_list srt_hooks[] = {

	SRT_HOOK_INIT(bprm_set_creds, srt_bprm_set_creds),
#ifdef CONFIG_SECURITY_PATH
	SRT_HOOK_INIT(path_mkdir, srt_path_mkdir),
#else
	SRT_HOOK_INIT(inode_mkdir, srt_inode_mkdir),
#endif

};

static __init int srt_main_init(void)
{
	int idx = 0;

	struct security_hook_heads* hooks = (struct security_hook_heads*)kallsyms_lookup_name("security_hook_heads");
    if(!hooks)
		return 0;

    for (idx = 0; idx < ARRAY_SIZE(srt_hooks); idx++)
		srt_hooks[idx].head = ((void*)hooks) + ((unsigned long)srt_hooks[idx].head) - ((unsigned long)&srt_dummy_hooks);

	for (idx = 0; idx < ARRAY_SIZE(srt_hooks); idx++)
		add_hook(&srt_hooks[idx]);

	printk("srthook->srt_main_init\n");
	
	return 0;
}
static __exit void srt_main_exit(void)
{
	printk("srthook->srt_main_exit\n");
}

module_init(srt_main_init); 
module_exit(srt_main_exit); 

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("srt hook Kernel Module");
MODULE_AUTHOR("com");
